# coding=utf-8
from flask import Blueprint
from model import ShopType
from utils.redis import Redis
import json
from datetime import datetime
from utils import restful
from utils.Lock import ExcludeLock
from setting import Prefixs
import threadpool  # 线程池模块

pool = threadpool.ThreadPool(1)

bp = Blueprint('shop-type', __name__, url_prefix='/shop-type')


def SetCache_ShopTypeList_forkThread(id):
    try:
        from app import app
        with app.app_context():  # 从数据库中拿到ShopType的全部数据并转换为可序列化的格式
            shop_type_list = [shop_type.to_dict() for shop_type in ShopType.query.all()]
        # 1 封装数据，添加expire字段代表过期时间
        shop_type_result = {'data': shop_type_list, "expire": datetime.now().timestamp() + 60 * 60 * 30}
        # 2 重建缓存
        Redis.set("shop_type_list", json.dumps(shop_type_result), expire=-1)
    finally:
        # 3 释放互斥锁
        ExcludeLock.unLock(Prefixs.lock_shoptype_list)
        # print("释放锁")



# 假如/shop-type/list 是热点数据，采用逻辑过期解决缓存击穿问题,为了方便调试把数据加载到缓存单独用一个视图实现SetShopTypeListCache
@bp.route('/list')
def queryTypeList():
    result = Redis.get("shop_type_list")
    # 1 拿不到缓存直接返回错误信息
    if not result:
        return restful.fail("没有相关信息！"), 404
    shop_type_result = json.loads(result)
    # 2 查看expire是否过期
    if datetime.now().timestamp() < shop_type_result['expire']:  # 如果没有过期，返回缓存结果
        return restful.success(data=shop_type_result['data'])
    # 3 否则说明过期了,尝试拿到互斥锁资源
    if not ExcludeLock.tryLock(Prefixs.lock_shoptype_list):
        # 3.1 没有拿到锁直接返回旧数据
        return restful.success(data=shop_type_result['data'])
    # 3.2 拿到了互斥锁资源，需要先fork一个子线程，然后在子线程中重建缓存，主进程直接返回旧的数据
    # thread = Thread(target=SetCache_ShopTypeList_forkThread)
    # thread.start()  # 开始运行子线程
    # -> 优化为线程池  如果ShopType.query.all()查询语句可以脱离app上下文还可以更快
    for task in threadpool.makeRequests(SetCache_ShopTypeList_forkThread, args_list=range(1)):
        pool.putRequest(task)
    # 4 主进程直接返回数据
    return restful.success(data=shop_type_result['data'])

# @bp.route('/list')
# def queryTypeList():
#     result = Redis.get("shop_type_list")
#     if result:
#         shop_type_list = json.loads(result)
#     else:
#         shop_types = ShopType.query.all()
#         shop_type_list = [shop_type.to_dict() for shop_type in shop_types]
#         Redis.set("shop_type_list", json.dumps(shop_type_list))
#     # print(json.loads(Redis.get("shop_type_list")))
#     return jsonify({"success": True, "data": shop_type_list})
